package main

import (
	"context"
	"gitee.com/lipore/go-nio/pkg/channel"
	"gitee.com/lipore/go-nio/pkg/frame"
	"gitee.com/lipore/plume/logger"
	"reflect"
	"strings"
)

type echoHandler struct {
}

func (e *echoHandler) HandleOutbound(ctx channel.OutboundContext) error {
	logger.Debugf("outbound: %v", ctx.OutboundBuffer().Bytes())
	return nil
}

func (e *echoHandler) HandleInbound(ctx channel.InboundContext) error {
	logger.Debugf("inbound: %s", string(ctx.Frame()))
	return nil
}

func (e *echoHandler) HandleDisconnect(ctx channel.DisconnectContext) error {
	logger.Debugf("%d disconnected", ctx.ChannelId())
	return nil
}

func (e *echoHandler) HandleConnect(ctx channel.ConnectContext) error {
	logger.Debugf("%d connected", ctx.ChannelId())
	return nil
}

type echoBackHandler struct {
}

func (e *echoBackHandler) HandleOutbound(_ channel.OutboundContext) error {
	logger.Debugf("echo back outbound")
	return nil
}

func (e *echoBackHandler) HandleInbound(ctx channel.InboundContext) error {
	logger.Debugf("echo back inbound")
	if reflect.DeepEqual(strings.Trim(string(ctx.Frame()), "\r"), "reverse") {
		_ = channelGroups.echo.Remove(ctx.Channel())
		_ = channelGroups.reverseEcho.Add(ctx.Channel())
	}
	ctx.Emit([]byte(ctx.Frame()))
	return nil
}

type reverseEchoBackHandler struct {
}

func (e *reverseEchoBackHandler) HandleOutbound(_ channel.OutboundContext) error {
	logger.Debugf("reverse echo back outbound")
	return nil
}

func (e *reverseEchoBackHandler) HandleInbound(ctx channel.InboundContext) error {
	logger.Debugf("reverse echo back inbound")
	if reflect.DeepEqual(strings.Trim(string(ctx.Frame()), "\r"), "reverse") {
		_ = channelGroups.reverseEcho.Remove(ctx.Channel())
		_ = channelGroups.echo.Add(ctx.Channel())
	}
	ctx.Emit(reverse(ctx.Frame()))
	return nil
}

func reverse(b []byte) []byte {
	l := len(b)
	a := make([]byte, l)
	for i := l; i > 0; i-- {
		a[l-i] = b[i-1]
	}
	return a
}

type cgs struct {
	echo        channel.Group
	reverseEcho channel.Group
}

var channelGroups *cgs

func CreateChannelGroups() channel.Groups {
	p1 := channel.NewPipeline(frame.DelimiterBasedFrameCodec(';', 0))
	p1.AddFirst(&echoHandler{}, &echoBackHandler{})
	p2 := channel.NewPipeline(frame.DelimiterBasedFrameCodec(';', 0))
	p2.AddFirst(&echoHandler{}, &reverseEchoBackHandler{})
	cg1, err := channel.NewGroup(context.Background(), p1, 10, 1)
	if err != nil {
		panic(err)
	}
	cg2, err := channel.NewGroup(context.Background(), p2, 10, 2)
	if err != nil {
		panic(err)
	}
	channelGroups = &cgs{
		echo:        cg1,
		reverseEcho: cg2,
	}
	return []channel.Group{cg1, cg2}
}
